; *****************************************************************
; Kernel Loader (RDKRLD.SYS) - Second Stage Boot Loader
; Reindeer OS - boot loader
;
; Note:
; Kernel image is loaded in real mode, so we are dealing with 1Mb memory barier,
; there must be some space for bios stuff, so we must load
; kernel image to memory buffer started at 0x37C00 (~230kB).
; These reason the max. kernel image size is about 700kB.
; In future  we must made real/protected mode switching so
; we can continuously transfer image data from real mode buffer
; to protected mode memory area.
; Our kernel now has about 50kB, so we don't need it yet :)
;
; Copyrights 2010-2011 Michal Saman, m.saman@designplus.cz.
; This source code is release under the Apache License 2.0.
; http://www.apache.org/licenses/LICENSE-2.0
; *****************************************************************

%define PRG_CODE_SEGMENT			0x0

%define READ_BUFF_SEG				0x37C0
%define	READ_BUFF_OFF				0x0000

; stack segment, offset
%define STACK_INIT_SEG				0x27C0
%define STACK_INIT_OFF				0xFFFF

; where kerlne is loaded in protected mode (1Mb)
%define K_IMAGE_PMODE_BASE		0x100000
;%define K_IMAGE_PMODE_BASE		0x887376

; where kernel will be loaded in real mode
%define	K_IMAGE_RMODE_BASE		0x37C00

; we are loaded at 0x0900:0x0000
org 0x9000
bits 16					; still in the real mode

jmp main

;************************
; Preprocesor includes
;************************
%include "boot/read_file_ext.inc.asm"
%include "boot/stdio16.inc.asm"
%include "boot/stdio32.inc.asm"
%include "boot/gdt.inc"
%include "boot/A20.inc"
%include "boot/fat12.inc.asm"
%include "boot/iso9660.inc.asm"
%include "boot/multiboot.inc"
%include "boot/memory.inc"

boot_info:
istruc mboot_info_type
	at mboot_info_type.flags,				dd 0
	at mboot_info_type.memoryLo,			dd 0
	at mboot_info_type.memoryHi,			dd 0
	at mboot_info_type.bootDevice,			dd 0
	at mboot_info_type.cmdLine,				dd 0
	at mboot_info_type.mods_count,			dd 0
	at mboot_info_type.mods_addr,			dd 0
	at mboot_info_type.sysm0,				dd 0
	at mboot_info_type.sysm1,				dd 0
	at mboot_info_type.sysm2,				dd 0
	at mboot_info_type.mmap_length,			dd 0
	at mboot_info_type.mmap_addr,			dd 0
	at mboot_info_type.drivers_length,		dd 0
	at mboot_info_type.drivers_addr,		dd 0
	at mboot_info_type.config_table,		dd 0
	at mboot_info_type.bootloader_name,		dd 0
	at mboot_info_type.apm_table,			dd 0
	at mboot_info_type.vbe_control_info,	dd 0
	at mboot_info_type.vbe_mode,			dw 0
	at mboot_info_type.vbe_interface_seg,	dw 0
	at mboot_info_type.vbe_interface_off,	dw 0
	at mboot_info_type.vbe_interface_len,	dw 0
iend

;****************************************
; STAGE 2 entry point
;	- Store BIOS informaiton
;	- Load Kernel
;	- Install GDT
;	- Jump to Stage 3
;****************************************
main:
	cli
	; setup segment and stack
	xor		ax, ax
	mov		ds, ax
	mov		es, ax
	mov		ax, STACK_INIT_SEG			; stack begins at 0x9000:0xFFFF
	mov		ss, ax
	mov		sp, STACK_INIT_OFF
	sti

	mov		[filesystem], bl
	mov 	[boot_drive], dl
	mov		[boot_info+mboot_info_type.bootDevice], dl
	mov		[iso_pri_vol_descriptor], cx

	mov		si, msgHeader
	call	Puts16

	mov		si, msg
	call	Puts16

	mov		si, msgGDTload
	call	Puts16

	call	InstallGDT

	mov		si, msgA20enb
	call	Puts16

	call	EnableA20_Kb_Out

	; Get Memory Size and store it in mboot_info structure
	xor		eax, eax
	xor		ebx, ebx
	call	BiosGetMemorySize64MB
	mov		word [boot_info+mboot_info_type.memoryHi], bx
	mov		word [boot_info+mboot_info_type.memoryLo], ax

	; Get memory map
	mov		eax, 0x0
	mov		ds, ax
	mov		di, 0x1000					; address where we save the memory map
	call	BiosGetMemoryMap

	; INIT file system
	mov		si, msgLoading
	call	Puts16

	cmp		BYTE [filesystem], 0
	je		.loadRootFat12
	cmp		BYTE [filesystem], 1
	je		.loadRootIso

.loadRootIso:
	call	loadFileIso
	;xor		ax, ax
	jmp		.loadFileDone
	;jmp		.loadError

.loadRootFat12:
	call	LoadRootFat12
	; load r-kernel
	mov		ebx, READ_BUFF_SEG
	mov		ebp, READ_BUFF_OFF
	mov		si, imageName_fat12
	call	LoadFileFat12

.loadFileDone:
	mov		dword [ImageSize], ecx			; save size of kernel image (in sectors!!)
	cmp		ax, 0							; Test for success
	je		StartPMode

.loadError
	mov		si, msgFailureLoadingKernel
	call	Puts16
	mov		ah, 0
	int		0x16			; wait for keypress
	int		0x19			; warm boot computer
	jmp	Stop

StartPMode:
	; go to protected mode
	cli
	mov		eax, cr0
	or		eax, 1
	mov		cr0, eax
	jmp		CODE_DESC:ProtectedMode

bits 32

ProtectedMode:
	mov		ax, DATA_DESC				; set segment registers to 0x10
	mov		ds, ax
	mov		ss, ax
	mov		es, ax
	mov		esp, 90000h					; stack begins from 90000h
	;call	GetCurPos
	;call	ClrScr32
	;mov		ebx, msgW32
	;call	Puts32
	;mov		ebx, msgStartingKernel
	;call	Puts32

CopyImage:
	mov		eax, dword [ImageSize]
	cmp		BYTE [filesystem], 0
	je		.fat12_copy
	cmp		BYTE [filesystem], 1
	je		.iso_copy
.fat12_copy
	movzx 	ebx, word [bpbBytesPerSector]
	push	ebx			; save sector size
	mul		ebx			; ax = ax * bx ; imagesize * bytesPerSector
	mov		ebx, 4
	div		ebx			; eax = eax / ebx ; proc to proboha delim 4 ????
	jmp		.start_copy
.iso_copy:
	movzx 	ebx, word [iso_sector_size]
	push	ebx			; save sector size
	mul		ebx			; ax = ax * bx ; imagesize * bytesPerSector
	jmp		.start_copy
.start_copy:
	cld
	mov		esi, K_IMAGE_RMODE_BASE
	mov		edi, K_IMAGE_PMODE_BASE
	mov		ecx, eax
	rep		movsd							; copy kernel from real mode address to protected mode adress

	cli										; force CPU to ignore maskable external interrupts

	mov		eax, 0x2BADB002					; magic number for multiboot spec.
	mov		ebx, 0							; should be zero by multiboot spec.
	mov		edx, [ImageSize]				; Size of KERNEL in memory, save it to DX
	pop		edi								; size of sector save to EDI
	push	dword boot_info					; save boot_info structure address to stack (for later usage by our kernel)
	push	esp								; save init_stack_add to stack (for later use by our kernel)

	call	CODE_DESC:K_IMAGE_PMODE_BASE	; EXECUTE KERNEL

Stop:
	cli
	hlt

;****************************
; Data section
;****************************

msgHeader				db		"Reindeer OS (c) Design PLUS 2010-2011", 13, 10, 0
msg						db		"R-Kernel Loader started", 13, 10, 0
msgGDTload				db		"Loading Global Description Table", 13, 10, 0
msgA20enb				db		"Enabling A20 line", 13, 10, 0
msgFailureLoadingKernel	db		13, 10, 13, 10, "Error loading kernel file (rkernel.img)", 0
msgProgress				db		".", 0
msgLoading				db		"Loading Kernel Image", 0
msgCrLf					db		13, 10, 0
msgW32					db		10,	".:: Welcome to 32 bit protected mode ::.", 10, 0
msgStartingKernel		db		"Starting R-KERNEL...", 0
ImageError				db		"*** FATAL ERROR: Invalid kernel image. Halting system.", 0

msgOK					db		"OK", 0
numberBuffer			db 		"12345678901234567890", 0					; memory for numToAscii conversion
filesystem				db		0
boot_drive				db		0



; kernel file name
imageName_fat12			db	"RKERNEL IMG"
imageName_iso			db	"RKERNEL.IMG;1"

; size of kernel image in sectors
ImageSize	db	0
